#ifndef _TBQUATERNION_H_
#define _TBQUATERNION_H_

#include "TBSettings.h"

#include "TBMath.h"
#include "TBVec3.h"

namespace tb
{

	class Mat3x3;
	class Mat4x4;

	class TB_DLL_FUNC Quat
	{

	public:

		// ================================
		// Static methods
		// ================================

		static Quat _IDENTITY;
		static Quat _FROMMATRIX(const Mat4x4& a_Matrix);

		// ================================
		// Constructors
		// ================================

		Quat();
		Quat(float a_X, float a_Y, float a_Z);
		Quat(float a_X, float a_Y, float a_Z, float a_W);
		Quat(const Vec3& a_Axis, float a_Degrees);

		// ================================
		// Methods
		// ================================

		void Identity();

		float GetSquaredLength() const;
		float GetLength() const;

		float GetDotProduct(const Quat& a_Other) const;

		Quat& Normalize();
		Quat GetNormalized() const;

		// Get the local x axis
		Vec3 GetTangent() const;

		// Get the local y axis
		Vec3 GetBitangent() const;

		// Get the local z axis
		Vec3 GetDirection() const;

		Quat& Conjugate();
		Quat GetConjugate() const;

		// ================================
		// Conversion
		// ================================

		Mat4x4 ToMat4x4() const;
		Mat4x4 ToMat4x4(float a_X, float a_Y, float a_Z) const;
		Mat4x4 ToMat4x4(const Vec3& a_Translation) const;

		// Returns a transposed version
		Mat4x4 ToCameraMatrix(const Vec3& a_Translation) const;
		Mat4x4 ToCameraMatrix(float a_X, float a_Y, float a_Z) const;

		Quat& FromMatrix(const Mat4x4& a_Matrix);
		Quat& FromAxes(const Vec3& a_X, const Vec3& a_Y, const Vec3& a_Z);
		Quat& FromAngleAxis(const Vec3& a_Axis, float a_Angle);

		// ================================
		// Rotation
		// ================================

		Vec3 Transform(const Vec3& a_Vector);

		// ================================
		// Interpolation
		// ================================

		Quat& Slerp(const Quat& a_Other, float a_Percentage);
		Quat GetSlerp(const Quat& a_Other, float a_Percentage) const;

		// ================================
		// Operators
		// ================================

		Quat& operator = (const Quat& a_Other);
		Quat& operator = (const Mat4x4& a_Other);

		Quat operator - () const;

		Quat operator * (const Quat& a_Other) const;
		Vec3 operator * (const Vec3& a_Transform) const;
		Quat operator * (float a_Value) const;
		
		Quat& operator *= (const Quat& a_Other);
		Quat& operator *= (float a_Value);

		// ================================
		// Data
		// ================================

		float x, y, z, w;

	}; // class Quaternion

}; // namespace tb

#include "TBQuat.inl"

#endif